Go言語の開発環境セットアップとサンプルプロジェクト作成
はじめに
Javaのエンジニアだった私がGo言語を始める上で学んだ開発環境のセットアップ方法についてまとめていきたいと思います。
Go言語をインストール後サンプルプロジェクトを作成し、Goのプロブラムの実行/ビルド方法や各種周辺ツールをご紹介していきます。
この記事がこれからGo言語で開発を始めたい方のとっかかりになれば幸いです。
※他言語で開発経験がある方を想定しております。
動作環境
今回使用した動作環境は以下のとおりです。
- PC : Mac M1(Apple Silicon)チップ
- OS : macOS Big Sir 11.5.2
- Go : 1.17.1
Go言語のインストール
始めはローカルPCで使用するGo言語のバージョンを簡単に切り替えれるようにgoenv
を使うつもりでしたが、以下の理由で思い止まりました。
- この記事を書いている最中、以前のバージョンのGoにセキュリティイシューが見つかった。最新バージョンとして1.17.1がリリースされたが、
goenv
に反映されるまで少し時間がかかりそうだった。実際に商用環境で稼働中のサービスを開発/運用している場合、このタイムラグは問題になりそう。 - Go言語は後方互換性についてのルールがあるため、「最新バージョンにアップデートしたら以前のバージョンで動いていたプログラムが動かなくなった。」というようなバージョンの違いによる問題が起こることはあまりなさそう。
- もしプロジェクトにより複数バージョンのGo言語を使い分けなくてはならないケースがあったとしても、公式でも複数バージョンを管理する方法が提供されている。参考リンク : Installing multiple Go versions、複数バージョンのGoをインストールする
セキュリティ的な事情等も考慮するといちはやく最新のバージョンに追随できる環境であることが望ましいと考え、今回は公式ページからInstaller版をダウンロードし最新バージョンのGo言語をインストールすることにしました。
Mac M1にGO言語をインストール方法の記事を参考にインストール後読み進めてください。
インストールが正常に完了したか下記コマンドで確認します。
% go version go version go1.17.1 darwin/amd64 % where go /usr/local/go/bin/go
Installer版でインストールした場合は、PATH等の設定も自動で行ってくれています。
下記コマンドで確認します。表示結果は私の環境の場合の設定です。
% echo $PATH | sed -e 's/:/\n/g' ~ /usr/local/go/bin ~
GOPATHについて
GOPATH
とは、外部パッケージやGoでビルドしたコンパイル済の実行プログラムなどが置かれる場所を定義する環境変数で、デフォルトではユーザホームディレクトリ内のgoフォルダ($HOME/go
)となっています。下記コマンドで確認できます。
% go env GOPATH
GOPATH
配下には以下のフォルダが作成されます。(Go言語をインストールしたばかりだと未作成)
- pkg : 外部パッケージなどが置かれます。 Javaでいうところの、ローカルのMavenリポジトリ(ユーザホームディレクトリの.m2フォルダ)のようなものと理解しています。
- bin : Goでビルドしたコンパイル済の実行プログラムなどが置かれます。
GOBIN
という環境変数でこの場所は変更可能です。
バージョン1.11以前は、GOPATH
配下にさらにsrcというフォルダがあり作成するGoのプログラムは全てこのフォルダに置くというルールで、実質$HOME/go/src
配下でしか開発できない状態だったようです。
バージョン1.11以降はGO111MODULE
という環境変数をon
に設定することで(1.16以降はデフォルトでon)この制約から開放され、$HOME/go/src
以外でも開発可能になっています。
またGOPATH
と似た概念でGOROOT
という環境変数もあります。
これはGoのSDKの場所を定義する環境変数で、以下のコマンドで確認できます。
% go env GOROOT
複数のバージョンのGoを使用しない限り変更することはないと思われますが、IDEなどの設定時にこのGOROOT
の場所を指定することがあります。
その他GOPATH
については以下の記事が勉強になりました。
サンプルプロジェクト
それではHello World的な簡単なサンプルプロジェクトを作成していこうと思います。
Go Modulesを使ったプロジェクト作成
Go Modulesは現在主流になっているパッケージ管理ツールです。
タスク自動化などの機能はありませんが、JavaのMaven/Gradle、Node.jsのnpmのような存在と理解しています。
任意のディレクトリで下記コマンドを実行すると新規プロジェクト(モジュール)を作成することができます。
% go mod init <モジュール名>
このコマンドを実行したフォルダがモジュールのルートディレクトリとなりgo.mod
というファイルが作成されます。
モジュール名は、Web上などに公開する場合は{Repository FQDN}/{Repository Path}/moduleA
のような命名規則となっています。公開しない場合はmoduleAのみでも問題ありません。
この記事では任意の場所に作成したhello-world
フォルダをルートディレクトリとし、モジュール名はgithub.com/hoge/hello-world
でgo mod init
コマンドを実行した前提で進めていきます。
% cd {任意のディレクトリ} % mkdir hello-world % cd ./hello-world % go mod init github.com/hoge/hello-world
その他Go Modulesに関する詳細は以下の記事が勉強になりました。
パッケージと構成
Goのソースコードに含まれる関数や変数は必ず1つのパッケージに属することになります。 また同じフォルダ内に属するファイルは全て同一のパッケージである必要があり、パッケージを1つにまとめたものがモジュールと呼ばれます。
このサンプルプロジェクトでは、下記の構成でファイルを配置してください。
hello-world/ ルートディレクトリ ┣ subpkg/ サブパッケージ = サブフォルダに置かれたパッケージ ┃ ┣ sub1.go ┃ ┗ sub2.go ┣ app.go ┣ main.go ┗ go.mod
サンプルコード
subpkgパッケージのファイル
package subpkg import ( "rsc.io/quote/v3" ) func Hello() (str string) { return quote.HelloV3() }
package subpkg func Golang() (str string) { return "Welcome to the Golang." }
sub1.go
4行目のrsc.io/quote/v3
はGo Modulesのサンプルによく使われている外部パッケージです。使用するには依存ファイルをダウンロードする必要があります。ダウンロード方法は後述します。
mainパッケージのファイル
package main func Goodbye() (str string) { return "Goodbye." }
package main import ( "fmt" "github.com/hoge/hello-world/subpkg" ) func main() { fmt.Println(subpkg.Hello()) fmt.Println(subpkg.Golang()) fmt.Println(Goodbye()) }
main
パッケージのmain
関数がエントリポイントとなります。main.go
5行目のようにサブパッケージをインポートする場合、モジュール名をルートディレクトリとしたフルパスで記載する必要があります。(公開しない場合はsubpkgのみで大丈夫です)main.go
9,10行目のように別のパッケージに属する関数を呼び出す場合はパッケージ名.関数名()で呼び出す必要があリますが、main.go
11行目のように同一パッケージの関数の場合は関数名()のみで呼べ出せます。実は同じパッケージに属するファイルであれば、分割しても同じファイルに記載しても動作的に全く影響はなく(単に読みやすいかや管理しやすいかという問題だけ)、app.go
のGoodbye
関数をmain.go
に定義しても何も動作は変わりません。
実行方法
実行前に外部パッケージのダウンロードを行います。ルートディレクトリで下記コマンドを実行してください。
% go get rsc.io/quote/v3
コマンド実行後、go.mod
ファイルにrequire
ディレクティブが追記されルートディレクトリ直下にgo.sum
というファイルが作成されます。go.sum
はインポートする外部パッケージのSHA-256 チェックサム値が格納され、インポートする外部パッケージの完全性を担保する役割を果たします。
またダウンロードされた外部パッケージは$GOPATH/pkg
配下に配置されます。
外部パッケージのダウンロード後、このサンプルは下記コマンドで実行できます。
% go run *.go Hello, world. Welcome to the Golang. Goodbye.
補足ですが、go run
コマンドは引数に指定したファイルのみを実行対象とする(ただしサブパッケージのファイルは含まれる)ので、今回のようにmain
パッケージのソースコードを分割した場合全てのファイルを引数に指定する必要があリます。下記のようにmain.go
のみを指定するとエラーとなります。
% go run main.go ./main.go:11:14: undefined: Goodbye
ビルド方法
下記コマンドで実行ファイルを作成することができます。
% go build
作成されたファイルを実行してみましょう。
% ls app.go go.mod go.sum hello-world main.go subpkg % ./hello-world Hello, world. Welcome to the Golang. Goodbye.
go install
go install
は実行ファイルを作成しさらに$GOPATH/bin
配下に配置するコマンドです。
% go install
コマンドを実行すると、$GOPATH/bin
配下(GOBIN配下)に実行ファイルが配置されます。
Installer版でGoをインストールした場合、デフォルトでPATHが通っているので、$GOPATH/bin
フォルダ以外でも実行ファイルがコマンドとして実行できます。
% cd ~ % hello-world Hello, world. Welcome to the Golang. Goodbye.
command not found
となる場合はTerminalを再起動してみてください。
このgo install
は、例えば開発チームで作った自作のコマンドラインツールを各チームメンバーに配布する際などに利用できそうです。
サンプルプロジェクトについては以上となります。
各種周辺ツールについて
gofmt/go fmt
gofmt
はGoが標準で提供しているコードフォーマッターです。設定項目が存在しないので単一のスタイルが強制されますが、独自のスタイルが乱立しないというメリットもあります。下記のように対象ファイルを指定して実行しますが、デフォルトだと整形後のソースコードが表示されます。
% gofmt main.go
-w
オプションを指定すると対象のファイルが直接書き換えられる挙動になり、さらに-l
オプションを指定すると修正を行ったファイル名を表示します。
似たようなコマンドでgo fmt
というコマンドがありますが、これはgofmt -l -w
と同じ挙動をします。
下記のコマンドでディレクトリ配下の全てのファイルにフォーマットをかけることができます。
% go fmt ./...
go vet
go vet
もGoが標準で提供している静的解析ツールで、バグの原因になりそうなコードを検出し警告してくれます。
go fmt
も同様ですが、ファイル指定、ディレクトリ指定、階層指定ができます。
% go vet main.go % go vet . % go vet ./...
goimports
goimports
はgofmt/go fmt
の上位互換のツールでコードフォーマットに加えて、不要なimportを削除するなど、import文を整理してくれます。
使用するには下記コマンドでインストールが必要です。
% go install golang.org/x/tools/cmd/goimports@latest
下記コマンドのように対象ファイル指定し実行します。-w
オプションを付けなかった場合、表示のみでファイルは修正されません。
% goimports -w main.go
goimports
コマンドはgo vet
のように階層指定ができないので、ディレクトリ配下の全てのファイルを整形にするには下記コマンドのようにする必要があります。また-local
オプションでimport文のソート順を指定することが可能です。下記コマンドは自作のサブパッケージが一番下に来るように指定しています。
% find . -print | grep --regex '.*\.go' | xargs goimports -w -local "github.com/hoge/hello-world"
staticcheck
staticcheck
はGoogleが公式でスポンサーをしているlintツールです。golint
というGoが標準で提供するlintツールもあるのですが、残念ながら開発が凍結されてしまいました。現在はstaticcheck
がgolint
に代わるlintツールとして主流になっています。各チェック項目の有効/無効も設定可能です。
使用するには下記コマンドでインストールが必要です。
% go install honnef.co/go/tools/cmd/staticcheck@latest
ファイル指定、ディレクトリ指定、階層指定ができます。
% staticcheck main.go % staticcheck . % staticcheck ./...
Makefile
Goではタスク自動化ツールとして、古くからGo以外でも使われるビルドツールのmake
がよく利用されています。
こちらのGo言語開発を便利にするMakefileの書き方の記事がとても参考になりました。
サンプルとして下記のようなファイルを作成してみました。ルートディレクトリ直下に置いてください。
format: @find . -print | grep --regex '.*\.go' | xargs goimports -w -local "github.com/hoge/hello-world" verify: @staticcheck ./... && go vet ./...
インデントがタブになっていないと実行時に*** missing separator. Stop.
というエラーが発生するので注意してください。
下記のようにMakefile
に定義したコマンドを実行できます。
% make format % make verify
最後に
所感ですが、GoはJavaと比べると開発環境の移り変わりが早いと感じました。
この記事の情報もすぐに鮮度が落ちると思うので、継続的に最新の開発トレンドを追いかけていく必要がありそうです。